/**
 * Copyright (c) 2006, PORTALIER Julien
 * 
 * Licensed under The LGPL License
 * Redistributions of files must retain the above copyright notice.
 * 
 * @package    FeatherCMS
 * @subpackage Javascript
 * @copyright  Copyright (c) 2006, Julien PORTALIER
 * @link       http://portalier.com/feather
 * @license    http://www.opensource.org/licenses/lgpl-license.php The LGPL License
 */

/*
Element.extend(
{
	preventEvent: function(action) {
		this.addEvent(action, function(evt) { new Event(evt).stop(); });
	}
});
*/

var Autocompleter = {};
Autocompleter.Base = new Class(
{
	initialize: function(input, url, options)
	{
		this.url    = url;
		this.tokens = [];
		this.token  = undefined;
		this.index  = 0;
		this.doSearch = true;
		
		this.options = {
			minChars: 1,
			tokenMark: ',',
			timeout: 500,
			paramName: 'value',
			className: 'autocomplete'
		};
		this.options = Object.extend(this.options, options || {});
		
		// elements
		this.input   = $(input);
		this.choices = new Element('div', {'class': this.options.className});
		
		// events
//		this.input.preventEvent('keyup');
//		this.input.preventEvent('keydown');
		this.input.addEvent('keypress', this.onKey.bind(this));
		
		this.input.addEvent('blur', this.clean.bind(this));
		this.choices.addEvent('mouseover', this.onMouse.bind(this));
		this.choices.addEvent('mousedown', this.onChoice.bind(this));
	},
	
	clean: function()
	{
		if (this.choices.parentNode) {
			this.choices.remove();
		}
		this.tokens = [];
		this.token  = undefined;
		this.index  = 0;
	},
	
	// requests
	
	search: function()
	{
		this.getToken();
		if (this.token.length >= this.options.minChars && !(/^\s*$/.test(this.token)) && !this.ajax)
		{
			this.ajax = new Ajax(this.url + '?' + this.options.paramName + '=' + encodeURIComponent(this.token),
			{
				method: 'get',
				onComplete: this.afterSearch.bind(this)
			}).request();
		}
	},
	
	afterSearch: function(html)
	{
		this.choices.setHTML(html.replace(new RegExp('/' + this.token + '/', 'ig'), '<span>' + this.token + '</span>'));
		
		var tokens = $ES('li', this.choices);
		if (tokens.length > 0)
		{
			this.choices.setStyles({
				position: 'absolute',
				'width': this.input.offsetWidth + 'px',
				'top':   this.input.offsetTop   + this.input.offsetHeight + 'px',
				'left':  this.input.offsetLeft  + 'px'
			}).injectAfter(this.input);
			
			var index   = 0;
			this.tokens = [];
			tokens.each(function(li)
			{
				this.tokens.push(li.innerHTML);
				li.index = index;
				index++;
			}, this);
			
			this.index = 0;
			this.selectChoice();
		}
		
		this.ajax = null;
	},
	
	// events
	
	onKey: function(evt)
	{
		evt = new Event(evt);
		this.specialKeys = this.specialKeys || [
			evt.KEY_DOWN,
			evt.KEY_UP,
			evt.KEY_LEFT,
			evt.KEY_RIGHT,
			evt.KEY_RETURN,
			evt.KEY_TAB,
			evt.KEY_DELETE,
			evt.KEY_BACKSPACE
		];
		var code = evt.key().code;
		
		switch(code)
		{
			case evt.KEY_DOWN:
				this.index = Math.min(this.index + 1, this.tokens.length - 1);
				this.selectChoice();
				evt.stop();
				return;
			
			case evt.KEY_UP:
				this.index = Math.max(this.index - 1, 0);
				this.selectChoice();
				evt.stop();
				return;
			
			case evt.KEY_RETURN:
				this.onChoice();
				evt.stop();
				return;
			
			case evt.KEY_ESC:
				this.clean();
				this.doSearch = false;
				evt.stop();
				return;
			
			default:
				this.doSearch = true;
		}

		if (this.doSearch && !this.specialKeys.test(code))
		{
			$clear(this.timeout);
			this.timeout = this.search.delay(this.options.timeout, this);
		}
	},
	
	onMouse: function(evt)
	{
		this.index = new Event(evt).target().index;
		this.selectChoice();
	},
	
	// choices
	
	selectChoice: function()
	{
		var choices = $ES('li', this.choices);
		var el = choices[this.index];
		if (el && !el.hasClass('selected'))
		{
			choices.each(function(li) { li.removeClass('selected'); });
			el.addClass('selected');
		}
	},
	
	onChoice: function()
	{
		this.setToken();
		this.clean();
	},
	
	// tokens
	
	getToken: function()
	{
		this.token = (this.input.value.indexOf(this.options.tokenMark) > -1) ?
			this.input.value.split(this.options.tokenMark).pop() :
			this.input.value;
		this.token = this.token.trim();
	},
	
	setToken: function()
	{
		var token = this.tokens[this.index];
		if (this.input.value.indexOf(this.options.tokenMark) > -1)
		{
			var tokens = this.input.value.split(this.options.tokenMark);
			
			for (var i = 0; i < tokens.length - 1; i++) {
				tokens[i] = tokens[i].trim();
			}
			tokens.pop();
			tokens.push(token);
			this.input.value = tokens.join(', ');
		}
		else {
			this.input.value = token;
		}
		this.input.value += ', ';
	}
});